import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Copyright (c) 2017-2018, Daniel Jiang (thorqq@163.com).
 *
 * Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3 (the "License");
 * 
 * Copyright (C) 2007 Free Software Foundation, Inc. [http://fsf.org/]
 */

/**
 * @author THORQQ
 *
 */
public class VideoUtils
{
	/**
	 * 获取音视频文件的信息
	 * @param file
	 * @return
	 */
	static public VideoInfo getVideoInfo(File file)
	{
		VideoInfo vi = new VideoInfo();
		vi.fullpath = file.getAbsolutePath();
		vi.filename = file.getName();


		List<String> command = new ArrayList<String>();
		command.add("ffmpeg.exe");
		command.add("-i");
		command.add(vi.fullpath);
		Utils.CommandResult cr = Utils.runCommand(command);
		
		String result = cr.output;
		if(result.contains("Invalid data found when processing input"))
		{
			return null;
		}

		// 通过视频流获取视频信息
		String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s";
		// String regexVideo ="Video: (.*?), (.*?), (.*?)[,\\s]";
		String regexVideo = "Video: (.*?), (.*?), (\\d*x\\d*)[,\\s]";
		String regexAudio = "Audio: (.*?), (\\d*) Hz";

		{
			Pattern pp = Pattern.compile(regexDuration);
			Matcher m = pp.matcher(result);
			if (m.find())
			{
				vi.duration = m.group(1);  // 播放时间  00:08:59.83
				vi.starttime = m.group(2); // 开始时间  0.000000
				vi.bitrate = m.group(3);   // bitrate 码率 单位 kb     205
			}
		}

		{
			Pattern pp = Pattern.compile(regexVideo);
			Matcher m = pp.matcher(result);
			if (m.find())
			{
				vi.vcode = m.group(1);   // 编码格式  h264 (High) (avc1 / 0x31637661)
				vi.vformat = m.group(2); // 视频格式  yuv420p
				vi.vpx = m.group(3);     // 分辨率    1280x720
			}
		}

		{
			Pattern pp = Pattern.compile(regexAudio);
			Matcher m = pp.matcher(result);
			if (m.find())
			{
				vi.acode = m.group(1);   // 音频编码     aac (LC) (mp4a / 0x6134706D)
				vi.asample = m.group(2); // 音频采样频率 48000
			}
		}
		
		return vi;
	}
	
	/**
	 * 截取视频，从start开始，持续duration
	 * @param src    源文件
	 * @param dest   目标文件
	 * @param start  起始时间
	 * @param duration  时长
	 * @throws Exception 
	 */
	static public void cutVideo(String src, String dest, float start, float duration) throws Exception
	{
        File file = new File(src);
        if (!file.exists()) 
        {
            throw new FileNotFoundException(src + " 文件不存在");
        }
        
        if (!src.endsWith(".mp4") && !src.endsWith(".avi")) 
        {
            throw new Exception("文件格式错误");
        }
        
        //https://blog.csdn.net/matrix_laboratory/article/details/53157383
        //ffmpeg视频精准剪切
    	//ffmpeg -ss 5 -t 531.83 -accurate_seek -i "1.1 软件入门知识.mp4" -codec copy -avoid_negative_ts 1 -y "1.1 软件入门知识-new.mp4"
		List<String> command = new ArrayList<String>();
		command.add("ffmpeg.exe");
		command.add("-ss");
		command.add("" + start);
		command.add("-t");
		command.add("" + duration);
		command.add("-accurate_seek");
		command.add("-i");
		command.add(src);
		command.add("-codec");
		command.add("copy");
		command.add("-avoid_negative_ts");
		command.add("" + 1);
		command.add("-y");
		command.add(dest);
		Utils.CommandResult cr = Utils.runCommand(command);
		if(cr == null)
		{
			System.out.println("Cut video error, file = " + src);
		}
		else
		{
			System.out.println("Process result: " + cr.exitValue + ", saved file: " + dest);
		}

	}
	
	static public void delogo(String src, String dest, int x, int y, int w, int h) throws Exception
	{
		File file = new File(src);
        if (!file.exists()) 
        {
            throw new FileNotFoundException(src + " 文件不存在");
        }
        
        if (!src.endsWith(".mp4") && !src.endsWith(".avi")) 
        {
            throw new Exception("文件格式错误");
        }
        
		//ffmpeg -i "2.2 基础图形绘制实例-new.mp4" -vf delogo=x=1057:y=8:w=214:h=52 "2.2 基础图形绘制实例-new2.mp4"
		List<String> command = new ArrayList<String>();
		command.add("ffmpeg.exe");
		command.add("-i");
		command.add(src);
		command.add("-vf");
		command.add(String.format("delogo=x=%d:y=%d:w=%d:h=%d", x, y, w, h));
		command.add("-y");
		command.add(dest);
		Utils.CommandResult cr = Utils.runCommand(command);
		if(cr == null)
		{
			System.out.println("Delogo video error, file = " + src);
		}
		else
		{
			System.out.println("Process result: " + cr.exitValue + ", saved file: " + dest);
		}
	}
	
	static public void addlogo(String src, String dest, String logopath, int x, int y) throws Exception
	{
		File file = new File(src);
        if (!file.exists()) 
        {
            throw new FileNotFoundException(src + " 文件不存在");
        }
        
        if (!src.endsWith(".mp4") && !src.endsWith(".avi")) 
        {
            throw new Exception("文件格式错误");
        }
        
		//ffmpeg –i "1.2 软件界面介绍及设定.mp4" -vf "movie=精品课程.png[watermark];[in][watermark]overlay=1057:8[out]" -y "1.2 软件界面介绍及设定-logo.mp4"
		List<String> command = new ArrayList<String>();
		command.add("ffmpeg.exe");
		command.add("-i");
		command.add(src);
		command.add("-vf");
		command.add(String.format("movie=%s[watermark];[in][watermark]overlay=%d:%d[out]", logopath, x, y));
		command.add("-y");
		command.add(dest);
		Utils.CommandResult cr = Utils.runCommand(command);
		if(cr == null)
		{
			System.out.println("addlogo video error, file = " + src);
		}
		else
		{
			System.out.println("Process result: " + cr.exitValue + ", saved file: " + dest);
		}
	}
	
	static public void replaceLogo(String src, String dest, String logopath, int x, int y, int w, int h) throws Exception
	{
		File file = new File(src);
        if (!file.exists()) 
        {
            throw new FileNotFoundException(src + " 文件不存在");
        }
        
        if (!src.endsWith(".mp4") && !src.endsWith(".avi")) 
        {
            throw new Exception("文件格式错误");
        }
        
        //ffmpeg -i "D:\BaiduNetdiskDownload\剪切\2.1 基本绘图工具.mp4" -vf "delogo=x=1057:y=8:w=214:h=52[in];movie=精品课程.png[watermark];[in][watermark]overlay=1057:8[out]" -y "1.2 软件界面介绍及设定-relogo.mp4"
        List<String> command = new ArrayList<String>();
		command.add("ffmpeg.exe");
		command.add("-i");
		command.add(src);
		command.add("-vf");
		command.add(String.format("delogo=x=%d:y=%d:w=%d:h=%d[in];movie=%s[watermark];[in][watermark]overlay=%d:%d[out]", x, y, w, h, logopath, x, y));
		command.add("-y");
		command.add(dest);
		Utils.CommandResult cr = Utils.runCommand(command);
		if(cr == null)
		{
			System.out.println("replacelogo video error, file = " + src);
		}
		else
		{
			System.out.println("Process result: " + cr.exitValue + ", saved file: " + dest);
		}
	}
	
	/**
     * 将字符串时间格式转换为整型，以秒为单位
     *
     * @param timeString 字符串时间时长
     * @return 时间所对应的秒数
	 * @throws Exception 
     */
	static public float parseTimeToSecond(String timeString) throws Exception 
    {
        Pattern pattern = Pattern.compile("\\d{2}:\\d{2}:\\d{2}.\\d{2}");
        Matcher matcher = pattern.matcher(timeString);
        if (!matcher.matches()) 
        {
            throw new Exception("时间格式不正确");
        }
        String[] time = timeString.split(":");
        return Integer.parseInt(time[0]) * 3600 
        		+ Integer.parseInt(time[1]) * 60 
        		+ Float.parseFloat(time[2]);
    }

    /**
     * 将秒表示时长转为00:00:00格式
     *
     * @param second 秒数时长
     * @return 字符串格式时长
     */
    static public String parseTimeToString(int second) 
    {
        int end = second % 60;
        int mid = second / 60;
        if (mid < 60) 
        {
            return mid + ":" + end;
        } 
        else if (mid == 60) 
        {
        	return "1:00:" + end;
        } 
        else 
        {
            int first = mid / 60;
            mid = mid % 60;
            return first + ":" + mid + ":" + end;
        }

    }
}
